using UnityEngine;
using System.Collections;


public class PlayerController : MonoBehaviour {
	public GameObject Bullet;
    public GameObject Bullet2;
    public GameObject Explosion;
    public GameObject Shard;
	
	public Texture DefaultTexture;
	public Texture DamagedTexture;
	public Texture DamagedTexture2;
	
	public float MaxHealth = 100.0f;
	public float MoveSpeed = 150.0f;
	public float RotSpeed = 50.0f;
	public float JumpPower = 5000.0f;
	public float RateOfFire = 0.16f;		// seconds to fire once
	public float MaxEnergy = 100.0f;		// max energy
	public float EnergyChargeRate = 100.0f;	// seconds to charge 100%
	public float EnergyConsumptionPerFire = 10.0f;
	
	private float Health;
	private float lastFiredTime;
	private float Energy;

    private bool isEnemy = false;

    private Hashtable bulletTab = new Hashtable();
    private int bulletIndex = 0;
    static int matBulletCount = 3000;
	// Use this for initialization
	void Awake () {
		Health = MaxHealth;
		Energy = MaxEnergy;
		ChangeHealth( 0 );
		ChangeEnergy( 0 );
		
		DefaultTexture = renderer.material.mainTexture;
		lastFiredTime = Time.timeSinceLevelLoad;
	}
	
	// Update is called once per frame
	void Update ()
	{
        if (isEnemy) return;

		// Recover Energy
		ChangeEnergy( EnergyChargeRate * Time.deltaTime );
		
		// if its in the air, add extra gravity
		bool onGround = Physics.Raycast( rigidbody.position, Vector3.down, 1 );
		float moveModifier = onGround ? 1.0f : 0.25f;
		if( !onGround )
		{
			rigidbody.drag = 1;
			rigidbody.AddForce( Vector3.down * 1.25f * Time.deltaTime * 60.0f, ForceMode.Impulse );
		}
		else{
			rigidbody.drag = 7;
		}

		// rotate
		rigidbody.AddRelativeTorque( Vector3.up * Input.GetAxisRaw( "Mouse X" ) * RotSpeed );
		
		// movement
		Vector3 vecForce = Vector3.zero;
		vecForce.x = Input.GetAxisRaw( "Horizontal" );
		vecForce.z = Input.GetAxisRaw( "Vertical" );
		rigidbody.AddRelativeForce( vecForce * MoveSpeed * Time.deltaTime * 60.0f * moveModifier, ForceMode.Acceleration );
		
		// on the floor? then Jump
		if( Input.GetButtonDown( "Jump" ) && onGround )
			rigidbody.AddForce( transform.up * JumpPower, ForceMode.Impulse );
		
		// fireing
		if( Input.GetButton( "Fire1" ) && Time.timeSinceLevelLoad >= lastFiredTime + RateOfFire && Energy >= EnergyConsumptionPerFire )
		{
            //Transform FirePos = transform.FindChild( "FireMuzzle" );
            //Transform bullet = (Transform) Instantiate( Bullet, FirePos.position, FirePos.rotation );
            //Physics.IgnoreCollision( bullet.collider , collider );
            //lastFiredTime = Time.timeSinceLevelLoad;
            //ChangeEnergy( -EnergyConsumptionPerFire );
            lastFiredTime = Time.timeSinceLevelLoad;
            ChangeEnergy(-EnergyConsumptionPerFire);
            networkView.RPC("Fire", RPCMode.All, ++bulletIndex % matBulletCount);
            //Fire();
		}
	}
    [RPC]
    void Fire(int bulletIndex)
    {
        Transform FirePos = transform.FindChild("FireMuzzle");
        GameObject bullet = MySpawner.Spawn(Bullet, FirePos.position, FirePos.rotation);
        Physics.IgnoreCollision(bullet.collider, collider);

        bullet.SendMessage("Init", new BulletInitInfo(this, bulletIndex));
        bulletTab[bulletIndex] = bullet;
    }

    void BulletCollision(int index)
    {
        networkView.RPC("BulletExplode", RPCMode.All, index);
    }

    [RPC]
    void BulletExplode(int index)
    {
        (bulletTab[index] as GameObject).SendMessage("Explode");
    }
	
	// Damage receiver
	void InflictDamage( float damage )
	{
        if (isEnemy) return;
		ChangeHealth( -damage );
	}
	
	private int lastHealthBar = 0;
	
	// Change Health
	void ChangeHealth( float amount )
	{
		Health += amount;
		if( Health < 0.0f )
			Health = 0.0f;
		if( Health > MaxHealth )
			Health = MaxHealth;

		// apply damaged texture
		if( Health < MaxHealth * 0.333 )
			renderer.material.mainTexture = DamagedTexture2;
		else if( Health < MaxHealth * 0.666 )
			renderer.material.mainTexture = DamagedTexture;
		else
			renderer.material.mainTexture = DefaultTexture;
		
		// Change Color	of health bar
		Color col;
		col.r = Mathf.Lerp( 1.0f, 0.333f, Health / MaxHealth );
		col.g = Mathf.Lerp( 0.333f, 1.0f, Health / MaxHealth );
		col.b = 0.333f;
		col.a = 0.75f;
		GameObject text = GameObject.Find( "HealthText" );
		text.renderer.material.color = col;
		
		// update Health Bar if changed
		int bar = Mathf.CeilToInt( Health / 10.0f );
		if( bar != lastHealthBar )
		{
			string txt = "";
			for ( int i=0; i<bar; i++ )
				txt += "I";

			TextMesh mesh = (TextMesh)text.GetComponent( "TextMesh" );
			mesh.text = txt;
			lastHealthBar = bar;
		}
	
		// dead?
		if( Health <= 0.0f )
			Death();

	}
	
	private int lastEnergyBar = 0;
	
	void ChangeEnergy( float amount )
	{
		Energy += amount;
		Energy = Mathf.Min( MaxEnergy, Mathf.Max( 0.0f, Energy ) );
		int bar = Mathf.CeilToInt( Energy / 10.0f );

		Color col;
		col.r = Mathf.Lerp( 1.0f, 0.333f, Energy / MaxEnergy );
		col.g = Mathf.Lerp( 0.333f, 1.0f, Energy / MaxEnergy );
		col.b = 0.333f;
		col.a = 0.75f;
		GameObject text = GameObject.Find( "EnergyText" );
		text.renderer.material.color = col;
		
		if( lastEnergyBar != bar )
		{
			string txt = "";
			for ( int i=0; i<bar; i++ )
				txt += "I";

			TextMesh mesh = (TextMesh)text.GetComponent( "TextMesh" );
			mesh.text = txt;
			lastEnergyBar = bar;
		}
	}
	
	
	// Die!!
	void Death()
	{
		ChangeEnergy( -Energy );
		
		// notify death to GameController 
		GameObject obj = GameObject.Find( "GameController" );
		obj.SendMessage( "NotifyPlayerDeath" );

        networkView.RPC("SelfExplosion", RPCMode.All);
	}

    [RPC]
    void SelfExplosion()
    {
        GameObject explosion = (GameObject)Instantiate(Explosion, transform.position, transform.rotation);
        explosion.renderer.material.color = this.renderer.material.color;

        for (int i = 0; i < 20; i++)
        {
            GameObject shard = (GameObject)Instantiate(Shard, transform.position, transform.rotation);
            shard.renderer.material.color = this.renderer.material.color;
            shard.transform.localScale = Vector3.one * Random.Range(0.25f, 0.5f);
            Vector3 pos;
            pos.x = transform.position.x + Random.Range(-2.0f, 2.0f);
            pos.y = transform.position.y + Random.Range(-1.0f, 1.0f);
            pos.z = transform.position.z + Random.Range(-2.0f, 2.0f);
            shard.rigidbody.MovePosition(pos);
            shard.rigidbody.AddExplosionForce(200.0f, transform.position, 50.0f);
        }

        DestroyObject(this.gameObject);
    }

    void OnNetworkInstantiate(NetworkMessageInfo info)
    {
        if (networkView.isMine)
        {
            renderer.material.color = new Color(56f/255f, 168f/255f, 254/255f);
        }
        else
        {
            isEnemy = true;
            renderer.material.color = Color.red;
            Bullet = Bullet2;
            gameObject.tag = "Enemy";
        }
    }

}
